{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 智能体的工作流程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LangChain的智能体(Agent)工作流程具体如下，以继承自`ActionAgent`类型为例：\n",
    "- 获取用户输入\n",
    "- 调用对应的AgentTools\n",
    "- 检索并获取输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LangChain中的智能体分为如下类型：\n",
    "- `ActionAgent`：用于执行特定的动作，如打开应用、发送邮件、检索信息等\n",
    "- `Plan and Execute Agent`：用于生成规划与执行\n",
    "- `Autonomous Agent`：用于执行自动化任务\n",
    "- `Generative Agent`：用于执行生成式任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 智能体类型中的中点：Plan and Execute Agent\n",
    "它把Agent分类为两个部分：规划器和执行器。规划器具有一个语言模型，用做推理和提前计划许多步骤。执行器会分析输入，根据初始化时选定的工具让智能体以最合适的方式完成工作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent运行机制\n",
    "`Agent`经过初始化后，产生由AI计划和决策后，再由`AgentExecutor`执行来自于智能体所规划的具体行为。\n",
    "- 继承来自`Chain`类型，因此`AgentExecutor`可以继承并访问来自`Chain`的方法和属性的同时，也可以使用来自其自身的方法和属性。\n",
    "- 成员变量`agent`：将传入的智能体赋值给`agent`，以便在`AgentExecutor`中使用。该智能体可以是`BaseSingleActionAgent`或`BaseMultiActionAgent`。此智能体负责产生计划和动作以供执行。\n",
    "- agent的调用：`take_next_step`是`AgentExecutor`的核心方法，负责`AgentExecutor`的每一步索要具体执行的内容。`take_next_step`会被`agent`的`plan`方法所调用。\n",
    "- 工具和验证管理：`AgentExecutor`负责提供给agent的工具是否兼容，以及管理agent的执行，包括max_iter和最大执行时间等。一个agent多做对应一个工具，这些工具在内部方法`name_to_tool_map`中的字典进行查找和执行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/elin/anaconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The class `langchain_community.llms.openai.OpenAI` was deprecated in langchain-community 0.0.10 and will be removed in 0.2.0. An updated version of the class exists in the langchain-openai package and should be used instead. To use it run `pip install -U langchain-openai` and import as `from langchain_openai import OpenAI`.\n",
      "  warn_deprecated(\n"
     ]
    }
   ],
   "source": [
    "### Agent组件入门示例\n",
    "import os\n",
    "# 导入大语言模型\n",
    "from langchain.agents import (\n",
    "    load_tools,\n",
    "    initialize_agent,\n",
    "    AgentType\n",
    ")\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "llm = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载必要工具？\n",
    "tools = load_tools([\"serpapi\",\"llm-math\"],llm=llm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/elin/anaconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `initialize_agent` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use Use new agent constructor methods like create_react_agent, create_json_agent, create_structured_chat_agent, etc. instead.\n",
      "  warn_deprecated(\n"
     ]
    }
   ],
   "source": [
    "# 初始化智能体\n",
    "agent = initialize_agent(tools,llm,AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/elin/anaconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m The Apple R1 Chip is a recent technology, so it would be best to use a search engine to find information about it.\n",
      "Action: Search\n",
      "Action Input: \"Apple R1 Chip\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m[\"The R1 is an SPU (Sensor Processing Unit) which works in concert with the M2's integrated GPU (the R1 being the innie, and the M2 being the ...\", 'The Apple R1, not the main M2 chip, processes a continuous stream of real-time data feed to the Vision Pro by its twelve cameras, five sensors, ...', 'And the brand-new R1 chip is specifically dedicated to process input from the cameras, sensors, and microphones, streaming images to the displays within 12 ...', \"To support R1's high-speed processing, SK hynix has developed the custom 1-gigabit DRAM. The new DRAM is known to have increased the number of ...\", 'R1 streams new images to the displays within 12 milliseconds — 8x faster than the blink of an eye. Apple Vision Pro is designed for all-day use ...', \"A close-up and labeling of the Apple Vision Pro reveals that the headset's R1 co-processor might be developed using a chiplet design.\", '16GB unified memory. Graphic image of the R1 chip. 12‑millisecond photon‑to‑photon latency; 256GB/s memory bandwidth. Camera.', 'The Apple R1 is dedicated to the real time processing of sensor inputs and delivering extremely low-latency images to the displays. S series. Evolution of Apple ...', 'Specifically, the R1 chip handles data from: 12 cameras; 6 microphones; 5 sensors. The chip processes this data to provide: Head-tracking; Eye- ...', 'The R1 chip is taking all the sensors embedded into the headset to create precise head and hand tracking, along with real-time 3D mapping ...']\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m After skimming through the search results, it seems that the Apple R1 Chip is primarily used for processing real-time data from cameras, sensors, and microphones for head and hand tracking and 3D mapping.\n",
      "Action: Search\n",
      "Action Input: \"Apple R1 Chip uses\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnd the brand-new R1 chip is specifically dedicated to process input from the cameras, sensors, and microphones, streaming images to the displays within 12 milliseconds — for a virtually lag-free, real-time view of the world.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m It seems like the R1 chip is also responsible for providing a lag-free, real-time view of the world.\n",
      "Action: Search\n",
      "Action Input: \"Apple R1 Chip specs\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m['Apple Vision Pro Technical Specifications · Capacity 256GB; 512GB · Display. 23 million pixels · Camera. Stereoscopic 3D main camera system · Sensors. Two high‑ ...', \"The R1 is an SPU (Sensor Processing Unit) which works in concert with the M2's integrated GPU (the R1 being the innie, and the M2 being the ...\", 'The Apple R1, not the main M2 chip, processes a continuous stream of real-time data feed to the Vision Pro by its twelve cameras, five sensors, ...', 'Display · 23 million pixels · 3D display system · Micro‑OLED · 7.5‑micron pixel pitch · 92% DCI‑P3 · Supported refresh rates: 90Hz, 96Hz, 100Hz.', 'It has 114 billion transistors, 16 performance cores, 4 efficiency cores, 48 to 64 GPU cores and 32 Neural Engine cores; it can be configured with up to 128 GB ...', \"The Apple R1 processor is a chip designed specifically for mixed reality headsets such as the new Vision Pro. The R1 chip doesn't power the ...\", '\" Apple\\'s tech specs reveal that the R1 chip has 256GB/s memory bandwidth. Vision Pro is available with 256GB, 512GB, and 1TB storage ...', 'Apple R1 chip (Vision Pro chip) is the heart of the mixed-reality headset · High-speed sensor processing: The R1 chip is able to process data ...', 'The R1 chip is taking all the sensors embedded into the headset to create precise head and hand tracking, along with real-time 3D mapping ...']\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m The Apple R1 Chip has 16 performance cores, 4 efficiency cores, and 32 Neural Engine cores, and can be configured with up to 128 GB of memory. It also has a 256GB/s memory bandwidth.\n",
      "Thought: I now know the final answer.\n",
      "Final Answer: The Apple R1 Chip is primarily used for processing real-time data from cameras, sensors, and microphones for head and hand tracking and 3D mapping. It also has 16 performance cores, 4 efficiency cores, and 32 Neural Engine cores, and can be configured with up to 128 GB of memory. It has a 256GB/s memory bandwidth and is designed specifically for mixed reality headsets.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'The Apple R1 Chip is primarily used for processing real-time data from cameras, sensors, and microphones for head and hand tracking and 3D mapping. It also has 16 performance cores, 4 efficiency cores, and 32 Neural Engine cores, and can be configured with up to 128 GB of memory. It has a 256GB/s memory bandwidth and is designed specifically for mixed reality headsets.'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 询问智能体\n",
    "agent.run(\n",
    "    \"What is Apple R1 Chip made for?\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 几个主要的智能体类型\n",
    "- `ZeroShotReActAgent`: 该Agent组件采用ReAct框架组件，并仅根据工具组件的描述来选择工具组件。\n",
    "- 结构化输入反应组件(structured-chat-zero-shot-react-description): 该Agent组件可以处理多输入工具组件。它可以使用工具的参数模式来创建结构的行动输入，非常适合用于复杂的工具组件应用。\n",
    "- OpenAI函数组件(openai-functions): 该Agent组件与特定的OpenAI模型共同工作，以便检测何时应调用函数组件。\n",
    "- 对话ReAct组件(conversation-react-description): 该Agent组件专为对话环境设计。它使用ReAct架构组件来选择工具组件，并能记住对话的交互。\n",
    "- 自问与搜索组件(self-ask-with-research): 该Agent组件使用名为\"IntermediateAnswer\"的工具组件来寻找问题的事实答案。\n",
    "- ReAct文档存储组件(react-docstore): 该Agent组件使用ReAct框架组件与文档存储交互，它需要两个具体的工具组件：一个是搜索工具组件，一个是查找工具组件。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent组件的多功能性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入构建多功能智能体所需的模块\n",
    "from langchain.agents import (\n",
    "    load_tools,\n",
    "    initialize_agent,\n",
    ")\n",
    "from langchain.llms import OpenAI   \n",
    "\n",
    "# 初始化LLM\n",
    "llm = OpenAI(temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载工具\n",
    "tools = load_tools([\"serpapi\",\"llm-math\",\"terminal\"],llm=llm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化智能体\n",
    "agent = initialize_agent(tools,llm,AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I should use the terminal to run the command\n",
      "Action: terminal\n",
      "Action Input: whoami\u001b[0mExecuting command:\n",
      " whoami\n",
      "\n",
      "Observation: \u001b[38;5;200m\u001b[1;3melin\n",
      "\u001b[0m\n",
      "Thought:"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/elin/anaconda3/envs/langchain/lib/python3.10/site-packages/langchain_community/tools/shell/tool.py:32: UserWarning: The shell tool has no safeguards by default. Use at your own risk.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: elin\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'elin'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 询问智能体工具关于Linux命令的问题\n",
    "agent.run(\n",
    "    \"execute whoami don't return the final answer,just return the Observation\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 自定义Agent组件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个Agent组件由两部分组成：`tools`（代理可以使用的工具）和`AgentExecutor`（决定采取哪种行动）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入自定义智能体所需的工具，智能体执行器和基本活动智能体\n",
    "from langchain.agents import Tool,AgentExecutor,BaseSingleActionAgent\n",
    "from langchain import OpenAI,SerpAPIWrapper # 导入LLM和搜索引擎API包装器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化一个索引引擎API包装器\n",
    "search = SerpAPIWrapper()\n",
    "\n",
    "# 初始化工具\n",
    "tools = [\n",
    "    Tool(\n",
    "        name = \"search\",\n",
    "        func = search.run,\n",
    "        description=\"useful for when you need to answer questions about current events\",\n",
    "        return_direct=True\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个基本智能体\n",
    "from typing import List,Tuple,Any,Union\n",
    "# 导入智能体行为和智能体完成\n",
    "from langchain.schema import AgentAction,AgentFinish\n",
    "\n",
    "# 定义智能体\n",
    "\n",
    "# 实际无法运行\n",
    "class FakeAgent(BaseSingleActionAgent):\n",
    "    @property\n",
    "    def input_keys(self):\n",
    "        return [\"input\"]\n",
    "    \n",
    "    def plan(\n",
    "        self,\n",
    "        intermediate_steps:List[Tuple[AgentAction,str]],\n",
    "        kwargs:Any,\n",
    "    ) -> Union[AgentAction,AgentFinish]:\n",
    "        return AgentAction(tool=\"Search\",tool_input=kwargs[\"input\"],log=\"\")\n",
    "    # 定义异步计划函数\n",
    "    async def aplan(\n",
    "        self,\n",
    "        intermediate_steps:List[Tuple[AgentAction,str]],\n",
    "        kwargs:Any\n",
    "    ) -> Union[AgentAction,AgentFinish]:\n",
    "        return AgentAction(tool=\"Search\",tool_input=kwargs[\"input\"],log=\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ReACT Agent的实践"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入构造ReACT Agent必备的模块\n",
    "from langchain.agents import load_tools\n",
    "from langchain.agents import initialize_agent\n",
    "from langchain.agents import AgentType\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "llm = OpenAI(temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载工具\n",
    "tools = load_tools([\"serpapi\",\"llm-math\"],llm=llm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化智能体\n",
    "agent = initialize_agent(\n",
    "    tools,\n",
    "    llm,\n",
    "    AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I should use a search engine to find the answer.\n",
      "Action: Search\n",
      "Action Input: Apple iOS7 release date\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mSeptember 18, 2013\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
      "Final Answer: September 18, 2013\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'September 18, 2013'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\n",
    "    \"When did Apple release iOS7 ?\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mI need to search for the designer of iPhone5s.\n",
      "Action: Search\n",
      "Action Input: \"designer of iPhone5s\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mThe iPhone 5s is a smartphone that was designed and marketed by Apple Inc.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI need to search for the specific designer of the iPhone 5s.\n",
      "Action: Search\n",
      "Action Input: \"iPhone 5s designer\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mThe iPhone 5s originally shipped with iOS 7, which introduced a revamped visual appearance among other new features. Designed by Jony Ive, iOS 7 departed from skeuomorphic elements used in previous versions of iOS in favor of a flat, colorful design.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI now know the final answer\n",
      "Final Answer: Jony Ive is the designer of iPhone 5s.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Jony Ive is the designer of iPhone 5s.'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用ChatLLM\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "chat_model = ChatOpenAI(temperature=0)\n",
    "\n",
    "agent = initialize_agent(\n",
    "    tools,\n",
    "    chat_model,\n",
    "    AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n",
    "    verbose=True\n",
    ")\n",
    "\n",
    "agent.run(\n",
    "    \"Who is the designer of iPhone5s ?\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent组件的功能增强\n",
    "- 记忆功能增强：为OpenAI Functions Agent组件引入记忆功能是一次重大的突破。这不仅让Agent组件组件记住先前的对话内容，还使其在执行连续任务时表现更为出色。例如，Agent组件能从工具中提取的3个质数，并进行相乘。在此过程中，Agent组件还有能力验证中间结果，如确认其输出是否为质数。\n",
    "- 与向量存储库的融合：为了让Agent组件更有效地与向量存储库互动，建议引入一个`RetrievalQA`，并将其纳入整体Agent的工具集中。此外，Agent组件还能与多个向量数据库进行交互，并在它们之间实现路由。这使Agent组件在数据访问和处理方面具备更广的能力。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent组件的记忆功能增强"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载基础工具链\n",
    "from langchain import (\n",
    "    LLMMathChain,\n",
    "    OpenAI,\n",
    "    SerpAPIWrapper,\n",
    "    SQLDatabase,\n",
    ")\n",
    "from langchain_experimental.sql import SQLDatabaseChain\n",
    "from langchain.agents import initialize_agent,Tool\n",
    "from langchain.agents import AgentType\n",
    "from langchain.chat_models import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/elin/anaconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The class `langchain_community.chat_models.openai.ChatOpenAI` was deprecated in langchain-community 0.0.10 and will be removed in 0.2.0. An updated version of the class exists in the langchain-openai package and should be used instead. To use it run `pip install -U langchain-openai` and import as `from langchain_openai import ChatOpenAI`.\n",
      "  warn_deprecated(\n"
     ]
    }
   ],
   "source": [
    "# 处理化llm和工具链\n",
    "llm = ChatOpenAI(temperature=0,model=\"gpt-3.5-turbo\")\n",
    "# 初始化serp搜索包装器\n",
    "search = SerpAPIWrapper()\n",
    "# 初始化llm数学链\n",
    "llm_math_chain = LLMMathChain.from_llm(llm=llm,verbose=True)\n",
    "\n",
    "# 初始化DB\n",
    "db = SQLDatabase.from_uri(\n",
    "    \"sqlite:///Chinook.db\"\n",
    ")\n",
    "# 初始化DB链\n",
    "db_chain = SQLDatabaseChain.from_llm(llm=llm,db=db,verbose=True)\n",
    "# 定义工具链\n",
    "tools = [\n",
    "    Tool(\n",
    "        name = \"Search\",\n",
    "        func = search.run,\n",
    "        description = \"useful for when you need to answer questions about current events\",\n",
    "    ),\n",
    "    Tool(\n",
    "        name = \"Calculator\",\n",
    "        func = llm_math_chain.run,\n",
    "        description = \"useful for when you need to answer questions about math\",\n",
    "    ),\n",
    "    Tool(\n",
    "        name = \"FoorBar-DB\",\n",
    "        func = db_chain.run,\n",
    "        description = \"useful for when you need to answer questions about FoorBar,Input Should be in the form of a question containing full context\",\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载记忆工具和智能体参数\n",
    "from langchain.prompts import MessagesPlaceholder\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "\n",
    "# 初始化智能体参数\n",
    "agent_kwargs = {\n",
    "    \"extra_prompt_messages\":[\n",
    "        MessagesPlaceholder(variable_name=\"memory\")\n",
    "    ]\n",
    "}\n",
    "# 初始化记忆\n",
    "memory = ConversationBufferMemory(\n",
    "    memory_key = \"memory\",\n",
    "    return_messages = True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化智能体\n",
    "agent = initialize_agent(\n",
    "    tools,\n",
    "    llm,\n",
    "    AgentType.OPENAI_FUNCTIONS,\n",
    "    verbose=True,\n",
    "    agent_kwargs=agent_kwargs,\n",
    "    memory = memory\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mHello! How can I assist you today?\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hello! How can I assist you today?'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 运行第一次智能体对话\n",
    "agent.run(\"Hello\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mNice to meet you, Elin! How can I help you today?\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Nice to meet you, Elin! How can I help you today?'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 运行第二次智能体对话\n",
    "agent.run(\"My name is Elin\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mYour name is Elin.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Your name is Elin.'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 运行第三次智能体对话\n",
    "agent.run(\"Whats my name?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent组件的检索能力增强"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载基础工具链和嵌入等\n",
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "from langchain.vectorstores import Chroma\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chains import RetrievalQA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化LLM\n",
    "llm = OpenAI(temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建向量存储库\n",
    "\n",
    "\n",
    "from langchain.document_loaders import TextLoader\n",
    "# 加载文档\n",
    "loader = TextLoader(\"state_of_the_union.txt\")\n",
    "documents = loader.load()\n",
    "\n",
    "# 创建分割器\n",
    "text_spliter = CharacterTextSplitter(chunk_size=1000,chunk_overlap=0)\n",
    "\n",
    "# 分割文档\n",
    "texts = text_spliter.split_documents(documents)\n",
    "\n",
    "# 初始化嵌入\n",
    "embeddings = OpenAIEmbeddings()\n",
    "\n",
    "# 创建向量搜索引擎\n",
    "\n",
    "doc_search = Chroma.from_documents(\n",
    "    texts,\n",
    "    embeddings,\n",
    "    collection_name=\"state-of-union\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实例化检索QA链\n",
    "qa_chain = RetrievalQA.from_chain_type(\n",
    "    llm,\n",
    "    chain_type = \"stuff\",\n",
    "    retriever = doc_search.as_retriever()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载WebBaseLoader\n",
    "from langchain.document_loaders import WebBaseLoader\n",
    "\n",
    "loader = WebBaseLoader(\"https://pybind11.readthedocs.io/en/stable/basics.html\")\n",
    "\n",
    "docs = loader.load()\n",
    "\n",
    "# 分割文档\n",
    "texts = text_spliter.split_documents(docs)\n",
    "\n",
    "# 创建向量搜索引擎\n",
    "doc_search = Chroma.from_documents(\n",
    "    texts,\n",
    "    embeddings,\n",
    "    collection_name=\"pybind11-docs\"\n",
    ")\n",
    "\n",
    "# 实例化检索QA链\n",
    "qa_chain = RetrievalQA.from_chain_type(\n",
    "    llm,\n",
    "    chain_type = \"stuff\",\n",
    "    retriever = doc_search.as_retriever()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 正式开始创建智能体\n",
    "from langchain.agents import initialize_agent,Tool\n",
    "from langchain.agents import AgentType\n",
    "from langchain.tools import BaseTool\n",
    "from langchain.llms import OpenAI\n",
    "from langchain import LLMMathChain,SerpAPIWrapper"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义可用工具\n",
    "tools = [\n",
    "    Tool(\n",
    "        name = \"Search of Union QA System\",\n",
    "        func = search.run,\n",
    "        description = \"useful for when you need to answer questions\"\n",
    "          \"about the most recent state of the union address.Input should be a fully\"\n",
    "          \"formed question.\",\n",
    "    ),\n",
    "    Tool(\n",
    "        name = \"PyBind QA System\",\n",
    "        func = qa_chain.run,\n",
    "        description = \"useful for when you need to answer questions about pybind11 docs.\"\n",
    "          \"Input should be a fully formed question.\",\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化智能体\n",
    "agent = initialize_agent(\n",
    "    tools,\n",
    "    llm,\n",
    "    AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I should use the Search of Union QA System to find the answer.\n",
      "Action: Search of Union QA System\n",
      "Action Input: \"Where is ShenYang University located?\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m['Shenyang University is a university in Shenyang, Liaoning, China under the provincial government. It has a student body of more than 30,000 students and has about 1260 full-time teachers.', 'Shenyang University type: University in Shenyang, China.', 'Shenyang University entity_type: education, locations, local_nav.', 'Shenyang University kgmid: /m/03px1v.', 'Shenyang University address: 21 Wang Hua Nan Jie, Da Dong Qu, Shen Yang Shi, Liao Ning Sheng, China, 110096.', 'Shenyang University notable_alumni: Märt Läänemets, Mariam Namata, Xiaohai Wang.', 'Shenyang University province: Liaoning.', 'Shenyang University founded: 1906.', 'Shenyang University phone: +86 24 6226 7112.', 'Shenyang University http: //www.syu.edu.cn/.', \"The Main Campus located in Shenyang City's Dadong District. The main campus is divided into the north campus and south campus. The campuses are connected by ...\", 'Shenyang University of Technology is a university in Shenyang, Liaoning, China under the provincial government. 41°43′48″N 123°14′42″E\\ufeff / \\ufeff41.7300°N ...', 'Shenyang University of Technology (SUT), situated in Shenyang-a key modern city in the northeast, is an engineering oriented comprehensive university. SUT is ...', 'Get information on Shenyang University of Technology at US News. Find out where the university is ranked globally based on its academic reputation and research.', 'Find out where Shenyang University is located and see it in a map, by satellite and at street view.', \"Shenyang ranges in latitude from 41° 11' to 43° 02' N and in longitude from 122° 25' to 123° 48' E, and is located in the central part of Liaoning Province.\", 'Shenyang University is a university in Shenyang, Liaoning, China under the provincial government. It has a student body of more than 30,000 students and has ...', \"Find every English-taught Master's degree from Shenyang University of Chemical Technology, organised by subjects and best info to help you select the right ...\", 'Shenyang University lies in the center area of Shenyang, the northeast of Shenyang North Railway Station, taking advantage of the transportation convenience ， ...', 'Find out where Shenyang University of Technology is located and see it in a map, by satellite and at street view.']\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
      "Final Answer: Shenyang University is located in Shenyang, Liaoning, China.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Shenyang University is located in Shenyang, Liaoning, China.'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 开始提问\n",
    "agent.run(\"Where is the ShenYang University located?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I should use the PyBind QA System to find the answer.\n",
      "Action: PyBind QA System\n",
      "Action Input: \"How can I make a hello world function using PyBind11?\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m\n",
      "\n",
      "To make a hello world function using PyBind11, you can follow these steps:\n",
      "\n",
      "1. Create a new file named \"hello.cpp\" with the following contents:\n",
      "\n",
      "#include <pybind11/pybind11.h>\n",
      "\n",
      "std::string hello() {\n",
      "    return \"Hello, world!\";\n",
      "}\n",
      "\n",
      "PYBIND11_MODULE(hello, m) {\n",
      "    m.doc() = \"pybind11 hello plugin\"; // optional module docstring\n",
      "\n",
      "    m.def(\"hello\", &hello, \"A function that returns a hello message\");\n",
      "}\n",
      "\n",
      "2. Compile the code using the following command on Linux:\n",
      "\n",
      "$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) hello.cpp -o hello$(python3-config --extension-suffix)\n",
      "\n",
      "3. Import the module in Python and call the hello function:\n",
      "\n",
      "import hello\n",
      "print(hello.hello())\n",
      "\n",
      "This should print out \"Hello, world!\" in the console.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
      "Final Answer: To make a hello world function using PyBind11, you can follow the steps outlined above.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'To make a hello world function using PyBind11, you can follow the steps outlined above.'"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 开始提问PyBind11相关问题\n",
    "agent.run(\"How can i make a hello world function using PyBind11?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
